import subprocess
import logging
import json
import os

from boto3.session import Session
from typing import Tuple


class FFmpegError(Exception):
    def __init__(self, message, status):
        super().__init__(message, status)
        self.message = message
        self.status = status

def exec_ffmpeg_cmd(cmd_lst):
    try:
        subprocess.run(
            cmd_lst, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
    except subprocess.CalledProcessError as e:
        err_log = f'''
        returncode: {e.returncode}
        cmd: {e.cmd}
        output: {e.output}
        stderr: {e.stderr}
        stdout: {e.stdout}
        '''
        logging.error(err_log)
        raise FFmpegError(e.output, e.returncode)


def parse_file_path(filename) -> Tuple[str, str, str]:
    (fileDir, tempfilename) = os.path.split(filename)
    (shortname, extension) = os.path.splitext(tempfilename)
    return fileDir, shortname, extension


def handler(event, context):
    evt = json.loads(event)
    first_evt = evt[0]
    first_split_keys = first_evt['split_keys']

    video_key = first_split_keys['video_key']
    video_process_dir = first_split_keys['video_proc_dir']
    video_type = first_split_keys['format']
    oss_bucket_name = 'workflow-bucket'
    output_prefix = 'workflow/video/dst'
    
    transcoded_split_keys = []
    for e in evt:
        split_keys = e['split_keys']
        fileDir, shortname, _ = parse_file_path(split_keys['filekey'])
        transcoded_filename = 'transcoded_%s.%s' % (shortname, video_type)
        transcoded_filepath = os.path.join(fileDir, transcoded_filename)
        transcoded_split_keys.append(transcoded_filepath)

    access_key = os.getenv("ZOS_ACCESS_KEY")
    secret_key = os.getenv("ZOS_SECRET_KEY")
    endpoint = os.getenv("ZOS_ENDPOINT")
    session = Session(access_key, secret_key)
    s3_client = session.client("s3", endpoint_url=endpoint)

    if len(transcoded_split_keys) == 0:
        raise Exception("no transcoded_split_keys")

    logging.info({
        "target_type": video_type,
        "transcoded_split_keys": transcoded_split_keys
    })

    _, shortname, extension = parse_file_path(video_key)
    segs_filename = 'segs_%s.txt' % (shortname + video_type)
    segs_filepath = os.path.join(video_process_dir, segs_filename)

    if os.path.exists(segs_filepath):
        os.remove(segs_filepath)

    with open(segs_filepath, 'a+') as f:
        for filepath in transcoded_split_keys:
            f.write("file '%s'\n" % filepath)

    merged_filename = 'merged_' + shortname + "." + video_type
    merged_filepath = os.path.join(video_process_dir, merged_filename)

    if os.path.exists(merged_filepath):
        os.remove(merged_filepath)

    exec_ffmpeg_cmd(['/opt/ffmpeg/ffmpeg', '-f', 'concat', '-safe', '0', '-i',
                     segs_filepath, '-c', 'copy', '-fflags', '+genpts', merged_filepath])

    logging.info('output_prefix ' + output_prefix)
    merged_key = os.path.join(output_prefix, shortname, merged_filename)
    s3_client.upload_file(merged_filepath, oss_bucket_name, merged_key)
    logging.info("Uploaded %s to %s" % (merged_filepath, merged_key))

    res = {
        "video_path": merged_key,
        "video_proc_dir": video_process_dir
    }

    return res
